﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.TeamFoundation.TestManagement.Client;
using Microsoft.TeamFoundation.Client;
using System.Threading;
using Microsoft.TeamFoundation.Lab.Workflow.Activities;

namespace HybridLab.Workflow.Activities.UI
{
	internal class RunTestDetailsEx : PropertyErrorManager
	{
		private Dictionary<int, List<ITestSuiteBase>> allTestSuites = new Dictionary<int, List<ITestSuiteBase>>();
		private List<ITestSettings> automatedTestSettingsList;
		private List<ITestSettings> currentTestSettingsList;
		private EventHandler InitializedHandler;
		private RunTestDetails details;
		private bool runTest;
		private TfsTeamProjectCollection server;
		private List<ITestSuiteBase> suites;
		private string teamProject;
		private ITestConfiguration testConfiguration;
		private ITestPlan testPlan;
		private ITestSettings testSettings;
		private ITestManagementTeamProject tcmProject;
		private List<ITestConfiguration> testConfigurationList;
		private List<ITestPlan> testPlanList;
		private List<ITestSuiteBase> testSuiteList;

		internal event EventHandler Initialized
		{
			add
			{
				EventHandler handler2;
				EventHandler initialized = InitializedHandler;
				do
				{
					handler2 = initialized;
					EventHandler handler3 = (EventHandler)Delegate.Combine(handler2, value);
					initialized = Interlocked.CompareExchange<EventHandler>(ref InitializedHandler, handler3, handler2);
				}
				while (initialized != handler2);
			}
			remove
			{
				EventHandler handler2;
				EventHandler initialized = InitializedHandler;
				do
				{
					handler2 = initialized;
					EventHandler handler3 = (EventHandler)Delegate.Remove(handler2, value);
					initialized = Interlocked.CompareExchange<EventHandler>(ref InitializedHandler, handler3, handler2);
				}
				while (initialized != handler2);
			}
		}

		internal RunTestDetailsEx(TfsTeamProjectCollection server, string teamProject, RunTestDetails testDetails)
		{
			if (server == null)
			{
				throw new ArgumentNullException("server");
			}
			if (string.IsNullOrEmpty(teamProject))
			{
				throw new ArgumentNullException("teamProject");
			}
			this.server = server;
			this.teamProject = teamProject;
			this.details = testDetails;
			if (this.details == null)
			{
				this.details = new RunTestDetails();
			}
			this.RunTest = this.details.RunTest;
		}

		internal void FilterTestSettings(List<string> roles)
		{
			if ((roles != null) && (roles.Count > 0))
			{
				CurrentTestSettingsList = AutomatedTestSettingsList.Where(settings =>
					{
						foreach (IMachineRole role in settings.MachineRoles)
						{
							if (!roles.Contains(role.Name, StringComparer.OrdinalIgnoreCase))
							{
								return false;
							}
						}
						return true;
					}).OrderBy(c => c.Name).ToList();
			}
			else
			{
				CurrentTestSettingsList = AutomatedTestSettingsList;
			}
		}

		internal RunTestDetails GetDetails()
		{
			RunTestDetails details = new RunTestDetails();
			details.RunTest = RunTest;
			details.TfsUrl = server.Uri.AbsoluteUri;
			details.ProjectName = teamProject;
			details.TestPlanId = (TestPlan != null) ? TestPlan.Id : -1;
			details.TestConfigurationId = (TestConfiguration != null) ? TestConfiguration.Id : -1;
			details.TestSettingsId = (TestSettings != null) ? TestSettings.Id : -1;
			details.TestSuiteIdList = new List<int>();
			if (Suites != null)
			{
				foreach (var suite in Suites)
				{
					details.TestSuiteIdList.Add(suite.Id);
				}
			}
			return details;
		}

		internal void InitializeData()
		{
			try
			{
				TestPlan = this.TestPlanList.FirstOrDefault<ITestPlan>(p => p.Id == details.TestPlanId);
				if (((TestPlan == null) && (TestPlanList != null)) && (TestPlanList.Count > 0))
				{
					TestPlan = TestPlanList[0];
				}
				TestConfiguration = TestConfigurationList.FirstOrDefault<ITestConfiguration>(c => c.Id == details.TestConfigurationId);
				TestSettings = AutomatedTestSettingsList.FirstOrDefault<ITestSettings>(s => s.Id == details.TestSettingsId);
                if (details.TestSuiteIdList != null && details.TestSuiteIdList.Count > 0)
                {
                    Suites = new List<ITestSuiteBase>();
                    using (List<int>.Enumerator enumerator = details.TestSuiteIdList.GetEnumerator())
                    {
                        while (enumerator.MoveNext())
                        {
                            int id = enumerator.Current;
                            ITestSuiteBase item = TestSuiteList.FirstOrDefault<ITestSuiteBase>(s => s.Id == id);
                            if (item != null)
                            {
                                Suites.Add(item);
                            }
                        }
                        base.RaiseEvent(InitializedHandler);
                    }
                }
                else
                {
                    InitializeSuites();
                }
				base.RaiseEvent(InitializedHandler);
			}
			catch (Exception exception)
			{
				OnError(exception);
			}
		}

		private void InitializeSuites()
		{
			Suites = new List<ITestSuiteBase>();
			if (TestPlan != null)
			{
				Suites.Add(TestPlan.RootSuite);
			}
		}

		internal void LoadTestPlans()
		{
			if (tcmProject == null)
			{
				tcmProject = this.server.GetService<TestManagementService>().GetTeamProject(this.teamProject);
			}
			string queryText = string.Format("SELECT * FROM TestSettings");
			AutomatedTestSettingsList = tcmProject.TestSettings.Query(queryText).Where<ITestSettings>(s => s.IsAutomated).OrderBy<ITestSettings, string>(c => c.Name).ToList();
			queryText = string.Format("SELECT * FROM TestConfiguration");
			this.TestConfigurationList = tcmProject.TestConfigurations.Query(queryText).OrderBy<ITestConfiguration, string>(c => c.Name).ToList();
			this.TestPlanList = tcmProject.TestPlans.Query("SELECT * from TestPlan").OrderBy<ITestPlan, string>(c => c.Name).ToList();
			ITestPlan plan = TestPlanList.FirstOrDefault<ITestPlan>(p => p.Id == this.details.TestPlanId);
			if (plan != null)
			{
				allTestSuites[plan.Id] = LoadTestSuiteForPlan(plan.Id).OrderBy<ITestSuiteBase, string>(c => c.Title).ToList();
			}
		}

		private List<ITestSuiteBase> LoadTestSuiteForPlan(int planID)
		{
			string queryText = string.Format("SELECT * FROM TestSuite WHERE PlanId = {0}", planID);
			return tcmProject.TestSuites.Query(queryText).ToList<ITestSuiteBase>();
		}

		private void OnError(Exception ex)
		{
		}

		private void UpdateTestSuites()
		{
			if (TestPlan != null)
			{
				List<ITestSuiteBase> list;
				if (allTestSuites.TryGetValue(TestPlan.Id, out list))
				{
					TestSuiteList = list;
				}
				else
				{
					TestSuiteList = this.allTestSuites[TestPlan.Id] = LoadTestSuiteForPlan(TestPlan.Id);
				}
			}
		}

		private void ValidateTestConfigurationList()
		{
			if (RunTest && ((this.TestConfigurationList == null) || (TestConfigurationList.Count == 0)))
			{
				base.SetPropertyError("TestConfigurationList", "No test configurations for current project");
			}
			else
			{
				base.ClearPropertyError("TestConfigurationList");
			}
		}

		private void ValidateTestPlanList()
		{
			if (RunTest && ((this.TestPlanList == null) || (TestPlanList.Count == 0)))
			{
				base.SetPropertyError("TestPlanList", "No test plans for current project");
			}
			else
			{
				base.ClearPropertyError("TestPlanList");
			}
		}

		private void ValidateTestSettingsList()
		{
			if (RunTest && ((automatedTestSettingsList == null) || (automatedTestSettingsList.Count == 0)))
			{
				base.SetPropertyError("AutomatedTestSettingsList", "No automated tests available for environment and project");
			}
			else if (RunTest && ((currentTestSettingsList == null) || (currentTestSettingsList.Count == 0)))
			{
				base.SetPropertyError("AutomatedTestSettingsList", "No automated test settings that match environment and project");
			}
			else
			{
				base.ClearPropertyError("AutomatedTestSettingsList");
			}
		}

		public List<ITestSettings> AutomatedTestSettingsList
		{
			get
			{
				return automatedTestSettingsList;
			}
			private set
			{
				automatedTestSettingsList = value;
				ValidateTestSettingsList();
			}
		}

		public List<ITestSettings> CurrentTestSettingsList
		{
			get
			{
				return currentTestSettingsList;
			}
			private set
			{
				currentTestSettingsList = value;
				ValidateTestSettingsList();
			}
		}

		internal bool RunTest
		{
			get
			{
				return runTest;
			}
			set
			{
				runTest = value;
				ValidateTestPlanList();
				ValidateTestSettingsList();
				ValidateTestConfigurationList();
			}
		}

		internal List<ITestSuiteBase> Suites
		{
			get
			{
				return suites;
			}
			set
			{
				suites = value;
			}
		}

		internal ITestConfiguration TestConfiguration
		{
			get
			{
				return testConfiguration;
			}
			set
			{
				testConfiguration = value;
			}
		}

		public List<ITestConfiguration> TestConfigurationList
		{
			get
			{
				return testConfigurationList;
			}
			private set
			{
				testConfigurationList = value;
				ValidateTestConfigurationList();
			}
		}

		internal ITestPlan TestPlan
		{
			get
			{
				return testPlan;
			}
			set
			{
				testPlan = value;
				UpdateTestSuites();
				InitializeSuites();
			}
		}

		public List<ITestPlan> TestPlanList
		{
			get
			{
				return testPlanList;
			}
			private set
			{
				testPlanList = value;
				ValidateTestPlanList();
			}
		}

		internal ITestSettings TestSettings
		{
			get
			{
				return testSettings;
			}
			set
			{
				testSettings = value;
			}
		}

		public List<ITestSuiteBase> TestSuiteList
		{
			get
			{
				return testSuiteList;
			}
			private set
			{
				testSuiteList = value;
			}
		}
	}
}